﻿using Core.DataAccess.Model;
using Core.Framework;
using Grain.Interfaces;
using Grain.State.BaseModule.StorgeStates;
using iTool.ClusterComponent;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Grain.Implements
{
    public class CloudRunningFunctionContainStateService : iToolServiceStorageBase<CloudRunningFunctionState>, ICloudRunningFunctionContainStateService
    {
        CloudRunningFunctionExtend extend;

        private IDBFactory iDBFactory;

        public CloudRunningFunctionContainStateService(IDBFactory iDBFactory)
        {
            this.iDBFactory = iDBFactory;
        }

        public async override Task OnActivateAsync()
        {
            this.extend = new CloudRunningFunctionExtend(this.GrainFactory);
            await base.OnActivateAsync();
        }

        public async Task<FunctionResult<dynamic>> InvokeExport(string exportedFunctionName, string channel, params object[] parameters)
        {
            TimeSpan ts1 = new TimeSpan(DateTime.Now.Ticks);

            bool isHavChannel = !string.IsNullOrWhiteSpace(channel);

            object[] args = isHavChannel
                ? await this.extend.GetFunctionParametersContainStateAsync(this.State.Data, channel, parameters)
                : this.extend.GetFunctionParametersContainState(this.State.Data, parameters);

            // 调用指定函数
            var resultJS = await NodeJS.InvokeExportAsync<dynamic>(this.State.ModulePath, exportedFunctionName, args);

            FunctionResult<dynamic> result = this.extend.GetFunctionResult(
                ts1,
                args[0] as SystemObject,
                resultJS);

            await this.extend.InvokeEndAsync(isHavChannel, channel, result);

            if (result.IsFinished)
            {
                var oldData = this.State.Data;

                try
                {
                    this.State.Data = result.State;

                    if (result.IsWriteState)
                    {
                        await this.WriteStateAsync();
                    }


                }
                catch (Exception ex)
                {
                    this.State.Data = oldData;
                    result.IsFinished = false;
                    result.Data = ex.Message;
                }
            }


            return result;
        }

        protected override Task ClearStateAsync()
        {
            return Task.CompletedTask;
        }

        protected override Task ReadStateAsync()
        {
            string stateKeyAndModuleName = this.GetStringKey();

            string[] arr = stateKeyAndModuleName.Split('_');

            (string stateKey, string moduleName) parameter = (arr[0], arr[1]);

            string modulePath = CloudDataConver.GetFunctionModulePathByModuleName(parameter.moduleName);

            this.State = new CloudRunningFunctionState();

            // 参数写入系统信息对象
            var systemObejct = new
            {
                State = string.Empty,
                notifys = new List<object>()
            };

            object[] args = new object[] { systemObejct, parameter.stateKey };

            // 获取状态信息
            var result = Task.Run(() => NodeJS.InvokeExportAsync<dynamic>(modulePath, "readstate", args)).Result;

            if (result.IsFinished)
            {
                this.State.StateKey = parameter.stateKey;
                this.State.ModulePath = modulePath;
                this.State.Data = result.Data.state;
                this.State.Initialization = true;
            }
            else
            {
                this.State.Data = result.Discription;
                this.State.Initialization = false;
            }

            return Task.CompletedTask;
        }

        protected override Task WriteStateAsync()
        {

            // 参数写入系统信息对象
            var systemObejct = new
            {
                State = this.State.Data
            };

            object[] args = new object[] { systemObejct };

            // 写入状态信息
            var result = Task.Run(() => NodeJS.InvokeExportAsync<dynamic>(this.State.ModulePath, "writestate", args)).Result;

            if (result.IsFinished)
            {
                this.State.Data = result.Data.state;
                return Task.CompletedTask;
            }
            else
            {
                throw new Exception(result.Discription);
            }
        }
    }
}
